using System;
using System.Collections;
using System.Text;
using Framework.Library.Core.Utils.Reflection;

namespace Framework.Library.Core.Utils.Miscellaneous
{
    public static class BitUtils
    {
        public const int ByteLength = 8;

        public static string BitArrayToString(BitArray bits)
        {
            var sb = new StringBuilder(bits.Length);

            for (int i = bits.Length - 1; i >= 0; i--)
            {
                bool bit = bits[i];

                sb.Append(Convert.ToInt32(bit));
            }

            return sb.ToString();
        }

        public static byte[] BitArrayToByteArray(BitArray bits)
        {
            return BitArrayToByteArray(bits, 0, bits.Length);
        }

        public static byte[] BitArrayToByteArray(BitArray bits, int startIndex, int count)
        {
            // Get the size of bytes needed to store all bytes
            int bytesize = count/ByteLength;

            // Any bit left over another byte is necessary
            if (count%ByteLength > 0)
                bytesize++;

            // For the result
            var bytes = new byte[bytesize];

            // Must init to good value, all zero bit byte has value zero
            // Lowest significant bit has a place value of 1, each position to
            // to the left doubles the value
            byte value = 0;
            byte significance = 1;

            // Remember where in the input/output arrays
            int bytepos = 0;
            int bitpos = startIndex;

            while (bitpos - startIndex < count)
            {
                // If the bit is set add its value to the byte
                if (bits[bitpos])
                    value += significance;

                bitpos++;

                if (bitpos%ByteLength == 0)
                {
                    // A full byte has been processed, store it
                    // increase output buffer index and reset work values
                    bytes[bytepos] = value;
                    bytepos++;
                    value = 0;
                    significance = 1;
                }
                else
                {
                    // Another bit processed, next has doubled value
                    significance *= 2;
                }
            }
            return bytes;
        }

        public static T Not<T>(T value, T not) // where T : IEquatable<T>
        {
            if (!GenericOperatorFactory<T, T, T, T>.And(value, not).Equals(default(T)))
                return GenericOperatorFactory<T, T, T, T>.Xor(value, not);

            return value;
        }
    }
}